<?php
/**
 * Groups module main class
 *
 * @access 	public
 * @author 	Valentin
 * @copyright	ResMania 2009 all rights reserved.
 * @link		http://developer.resmania.com/api
 */
class RM_Module_Groups extends RM_Module implements RM_Search_Advanced_Interface, RM_System_Setup
{
    /**
     * This presents an ID of a new unit config field for internal use
     */
    const UNIT_GROUP_ID_FIELD_ID = 40;

    public function  __construct() {
        $this->name = 'Groups';
    }

    function preDispatch()
    {
        /*
        //Uncomment me if you want to init simple unit rows for the admin end
        if (RM_Environment::getInstance()->getConnector()->getModule() == 'admin') {
            return;
        }
        */
        RM_Units::setDefaultRowClass('RM_Groups_Unit_Row');
    }

    public function disable()
    {
        throw new RM_Exception(RM_Environment::getInstance()->getTranslation()->_('Admin.Groups.Main', 'DisableAlert'));
    }

    /**
     * Returns all unit ids that don't belong to group and all units that
     * are main unit of the group
     *
     * @param RM_Unit_Search_Criteria $criteria
     * @return array, false.
     * If FALSE then all unit are passed,
     * if array - array with unit IDs, if empty array - none of the units are passed
     */
    function getAdvancedSearchUnitIDs(RM_Unit_Search_Criteria $criteria){
        //We need to return all units if we are on the admin end
        if (RM_Environment::getConnector()->getModule() == 'admin') {
            return false;
        }

        // create objects
        $unitModel = new RM_Units();
        $groupsModule = new RM_Groups();
        $groupsRow = new RM_Groups_Row();


        // get all the reserved Units for the selected period - we use this for availability checking throughout this process.
        $reservedUnitIDs = array();
        if ($criteria->start_datetime && $criteria->end_datetime) {
            $reservationPeriod = new RM_Reservation_Period(
                new RM_Date(strtotime($criteria->start_datetime)),
                new RM_Date(strtotime($criteria->end_datetime))
            );
            $reservedUnits = $unitModel->getReservedUnits($reservationPeriod);
            foreach ($reservedUnits as $unit) {
                    $reservedUnitIDs[] = $unit->getId();
            }

            $unitsWithAvailbilityCheckDisabled = RM_Environment::getInstance()->getPriceSystem()->getUnitWithAvailabiltyCheckDisabled();
            foreach ($unitsWithAvailbilityCheckDisabled as $mustShowUnit){
                $IgnoreReservedUnitIDs[] = $mustShowUnit['id'];
            }
        }

        if (isset($IgnoreReservedUnitIDs)){
            $reservedUnitIDs = array_diff($reservedUnitIDs, $IgnoreReservedUnitIDs);
        }

        // get non group units...
        $select = $unitModel->select()->where('group_id IS NULL');
        $units = $unitModel->fetchAll($select);

        // $nonGroupUnitIDs contains only available non-group units
        $nonGroupUnitIDs = array();
        foreach ($units as $unit) {
            if (array_search($unit->getId(), $reservedUnitIDs) === false){
                $nonGroupUnitIDs[] = $unit->getId();
            }
        }

        // change the where clause if we are checking on a particular group
        $where = 'group_id IS NOT NULL'; // default value
        if ($criteria->mainUnit){
            $groupid = $criteria->mainUnit->getGroupId();
            $where = 'group_id = '.$groupid;
        }
        // get Zend_DB_Table_Select
        $select = $unitModel->select()->where($where);


        // set ordering rules
        if ($criteria->order == 'random') {
            $sessionID = session_id();
            $random = hexdec($sessionID[0]);
            $select->order('RAND('.$random.')');
        }

        // get all units assigned to a group
        $units = $unitModel->fetchAll($select);

        // go through all the units and get the main (master) units...
        foreach ($units as $unit){
            $isMain = $groupsModule->isMain($unit);
            if ($isMain) {

                // save the main unit to the $mainUnits array
                $mainUnits[] = $unit->getId();

                // if $subunits>0 then add to $mainUnits else add the unit to $nonGroupUnitIDs
                // if we have a master unit that has no subunits then subunits will = 1
                $subunits = 0;
                foreach ($units as $unitRow){
                    if ($unitRow->getGroupId() === $unit->getId()){
                        $subunits +=1;
                    }
                }
                if ($subunits == 1){
                    // if there are no subunits treat the master like a non-group unit.
                    $nonGroupUnitIDs[] = $unit->getId();
                }
            }
        }

        // merge the masters and the reserved ID's together, as we want to check
        // for ONLY availble units and sub units first
        if (!empty($mainUnits)){
            $ALLreservedUnitIDs = array_merge($mainUnits, $reservedUnitIDs);
        } else {
            $ALLreservedUnitIDs = $reservedUnitIDs;
        }

        // $groupUnitIDs contains only available sub group units
        $groupUnitIDs = array();
        foreach ($units as $unit){
            $x = $groupsModule->getByUnit($unit);
            $masterID = $unit->getId();
            if (array_search($masterID, $ALLreservedUnitIDs) === false){
                if ($criteria->availabilityCheckOnly){
                    $groupUnitIDs[] = $masterID; // build an array with all the master unit ids only
                } else {
                    $groupUnitIDs[] = $unit->id; // build an array with all the real unit ids
                }
            }
        }

        // finally if we haven't got anything available then check our master units for availability
        if (!empty($mainUnits)){
            if (count($groupUnitIDs)===0){
                // now see if a master group unit is available
                foreach ($mainUnits as $unit){
                    if (array_search($unit, $reservedUnitIDs) === false){
                        $groupUnitIDs[] = $unit;
                    }
                }
            }
        }


        if (!$criteria->groupsOnly){
            $unitIDs = array_merge($nonGroupUnitIDs, $groupUnitIDs);
        } else {
            $unitIDs = $groupUnitIDs;
        }

        $unitIDs = array_unique($unitIDs);

        return $unitIDs;
    }

    public function install() {
        parent::install();

        $languageModule = new RM_Languages();
        $languages = $languageModule->fetchAll();
        require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'Groups.php');
        $groupsModule = new RM_Groups();
        foreach ($languages as $language){
            $groupsModule->addLanguage($language->iso);
        }

        $unitTypesModel = new RM_UnitTypes();
        $types = $unitTypesModel->fetchAll();

        $unitTypeConfigModel = new RM_UnitTypeConfig();
        foreach ($types as $type) {
            $unitTypeConfigModel->createRow(array('unit_type_id' => $type->id, 'unit_config_id' => self::UNIT_GROUP_ID_FIELD_ID))->save();
        }
    }

    /**
     * This method will return node object for main admin menu tree.
     * We override the parent class method to set ListJson action instead of default EditJson
     *
     * @return stdClass
     */
    public function getNode(){
        $std = new stdClass;

        $std->id = $this->name.'_ListJson_NoAjax';
        $std->text = $this->getName();

        $std->iconCls = 'RM_modules_leaf_icon';
        $std->leaf = 'true';
        return $std;
    }

    /**
     * We don't want to show config node for Groups module (for now)
     *
     * @return null
     */
    public function getConfigNode()
    {
        return null;
    }

    /**
     * This method will invoke while adding new language to the Resmania
     *
     * @param string $iso ISO language code
     */
    public function addLanguage($iso)
    {
        parent::addLanguage($iso);
        $model = new RM_Groups();
        $model->addLanguage($iso);
    }

    /**
     * Invokes after user delete language, make some changes for price module
     *
     * @param string $iso ISO language code
     * @return null
     */
    public function deleteLanguage($iso)
    {
        parent::deleteLanguage($iso);
        $model = new RM_Groups();
        $model->deleteLanguage($iso);
    }
}